<template>
  <div class="validate-input-container pd-3">
    <!--用.is-invalid和.is-valid指示无效和有效的表单字段-->
    <!--$attrs获取到父组件绑定的属性-->
    <!--将添加搭配父元素身上的属性放到子元素上，只需要做两件事
          1．把父元素的属性删除inheritAttrs:fasle
          2．使用v-bind="$attrs”绑定上元素
          -->
    <input v-if="tag !== 'textarea'" type="text" class="form-control" :class="{ 'is-invalid': inputRef.error }"
      v-bind="$attrs" @blur="validateInput" :value="inputRef.val" @input="updateValue" />
    <textarea v-else class="form-control" :class="{ 'is-invalid': inputRef.error }" v-bind="$attrs" :value="inputRef.val"
      @blur="validateInput" @input="updateValue"></textarea>
    <span class="invaild-feedback" v-if="inputRef.error">{{ inputRef.message }}</span>
  </div>
</template>

<script lang="ts">
import { defineComponent, reactive, PropType, onMounted, watch } from 'vue'
import { emitter } from "./ValidateForm.vue";

const emailReg = /^[a-zA-Z0-9.!#$%&’*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/

//邮箱规则
interface RuleProp {
  //required:必填项  email:email邮箱类型
  type: 'required' | 'email' | 'custom', //他可以同时实现两种，必选的|必填的
  message: string
  validator?: () => boolean
}

// RulesProp是在 RuleProp的基础上扩展的
//type起别名
export type RulesProp = RuleProp[]

export type TageType = 'input' | 'textarea'

export default defineComponent({
  props: {
    //我们在上边已经定义了它是一个数组
    rules: Array as PropType<RulesProp>,
    modelValue: String,
    tag: {
      type: String as PropType<TageType>
    }
  },
  setup(props, context) {
    //邮箱验证
    const inputRef = reactive({
      //如果它一开始有值的话，应该在你的 modelValue取值
      //如果刷新页面你的 input 里面有值是不是要在页面显示出来，显示出来的就是'props
      val: props.modelValue || '', //内容  它应该是有这两种情况的
      error: false, //返回有个错误，就是给他一个错误信息
      message: '' //返回有个错误信息
    })
    //你往里面输入内容鼠标只起到了一个失焦和获焦的作用
    // 你输入内容应该是你的键盘事件  KeyboardEvent
    const updateValue = (e: KeyboardEvent) => {
      // HTMLInputElement是input标签的这个元素
      // 就是拿到你的数据源推断它是不是当前的元素，然后取到 value 值赋给targetValue
      const targetValue = (e.target as HTMLInputElement).value
      inputRef.val = targetValue
      //子传父
      context.emit('value', targetValue)
    }

    // 监听编辑文章的信息
    watch(() => props.modelValue, (newVal) => {
      inputRef.val = newVal || ''

    })

    //当邮箱表单失焦时 @blur
    const validateInput = () => {
      if (props.rules) {
        const allPassed = props.rules.every((rule) => {
          let passed = true
          inputRef.message = rule.message
          switch (rule.type) {
            case "required":
              //不为空才能通过 返回为true
              passed = inputRef.val.trim() !== ''
              break;
            //  邮箱规则
            case "email":
              passed = emailReg.test(inputRef.val)
              break;
            case "custom":
              passed = rule.validator ? rule.validator() : true
              break;
            default: //如果上面都不符合
              break;
          }
          //把最后结果返回出去
          return passed
        })
        inputRef.error = !allPassed
        return allPassed
      }
    }
    onMounted(() => {
      //去执行你绑定的那个事件，将验证函数传出
      emitter.emit('form-item-created', validateInput)
    })

    return {
      inputRef,
      validateInput,
      updateValue
    }
  }
})
</script>

<style scoped></style>